#include "ustc_comdef.h"
#include "ustc_custom.h"
#include "ustc_api.h"
#include "ustc_hif.h"
#include "ustc_sd_drv.h"

/*default parameters

	ustc_sdc_init_delay1: 1  (20us)
	ustc_sdc_init_delay2: 50  (1ms)
*/

SD_PARA_T * gp_para_sd;

static USTC_U32 sd_wait_cmd_done(USTC_U8 crc_check_flag)
{
	USTC_U32 sd_status;
	USTC_U32 count;
	
	sd_status = USTC_IO_INW(HW_SD_STATUS);
	count = 0;
	//WAIT not busy
	while ( (sd_status & SD_CMD_DONE_CMD_BUSY) && (!(sd_status & SD_CMD_DONE_TIMER_ERR) ))
	{
		sd_status = USTC_IO_INW(HW_SD_STATUS);
		if (count++ >= SD_CMD_TIME_OUT)
			return RSP_SD_CMD_TIMEOUT;
	}
	//wait cmd done
	if (!(USTC_IO_INWM(HW_SD_STATUS,SD_CMD_DONE_TIMER_ERR)))
	{
		for (count=0; count<SD_CMD_TIME_OUT; count++)
			if (USTC_IO_INWM(HW_SD_STATUS,SD_CMD_DONE_MASK))
				break;
		if (count >= SD_CMD_TIME_OUT)
			return RSP_SD_CMD_TIMEOUT;
	}
	sd_status = USTC_IO_INW(HW_SD_STATUS);
	if (crc_check_flag)		
	{
		if ((sd_status&SD_CMD_DONE_CRC_ERR)==SD_CMD_DONE_CRC_ERR)
		{
			return RSP_SD_CMD_CRC_ERR;
		}
	}
	if ((sd_status&SD_CMD_DONE_TIMER_ERR)==SD_CMD_DONE_TIMER_ERR)		
	{
		return RSP_SD_CMD_TIMEOUT;
	}
	USTC_IO_OUTW(HW_SD_STATUS,SD_CMD_DONE_MASK);

	return RSP_SUCCESS;
}

static STATUS_T sd_wait_data_done(void)
{
	USTC_U32 sd_status;
	USTC_U32 count = 0;
	
	sd_status = USTC_IO_INW(HW_SD_STATUS);\
	while ( (sd_status&SD_DATA_TX_BUSY) && (!(sd_status & (SD_CMD_DONE_TIMER_ERR|SD_DATA_DONE_TIMEOUT))) )
	{
		sd_status = USTC_IO_INW(HW_SD_STATUS);
		if (count++ >=gp_para_sd->sd_timeout)
			return RSP_SD_DATA_TIMEOUT;
	}
	if (!(USTC_IO_INWM(HW_SD_STATUS,SD_CMD_DONE_TIMER_ERR|SD_DATA_DONE_TIMEOUT)))
	{
		for (count=0; count<gp_para_sd->sd_timeout; count++)
			if (USTC_IO_INWM(HW_SD_STATUS,SD_DATA_DONE_MASK))
				break;
	}
	sd_status = USTC_IO_INW(HW_SD_STATUS);
	USTC_IO_OUTW(HW_SD_STATUS,SD_DATA_DONE_MASK);
	
	if (sd_status & SD_DATA_DONE_NORMAL)
		return RSP_SUCCESS;
	else
		return RSP_SD_DATA_ERR;
}

/*===========================================================================
FUNCTION:  ustc_sdc_card_detect

DESCRIPTION: 
  	check card exists or not
INPUT PARAMETER:

OUTPUT PARAMETER:  

RETURN VALUE:
===========================================================================*/
STATUS_T ustc_sdc_card_detect(void)
{
	STATUS_T status = RSP_SUCCESS;
	USTC_U32 count;


	if (NULL == gp_para_sd)
	{
		return status;
	}
	
	
	do
	{
	USTC_IO_OUTW(HW_SD_CMD_ARG, gp_para_sd->sd_rca); 
	USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD13);	

	/* send cmd */
	status = sd_wait_cmd_done(1);
	if (status!= RSP_SUCCESS)
			break;

	
	/* judge response */
	count=0;
	while (!USTC_IO_INWM(HW_SD_RSP_ARG1, SD_RDY4DATA))
	{
		if(++count>=SD_CMD_TIME_OUT) 
		{
			status=RSP_SD_CMD_RSP_ERR;
			break;
		}
	}

	if (RSP_SUCCESS==status) 
	{
		/* if response is received,judge the state of sd card  */
		if (USTC_IO_INWM(HW_SD_RSP_ARG1, SD_CARD_STATE)!=SD_CARD_STATE_TRAN)
			status=RSP_SD_CMD_RSP_ERR;
	}
	}while (0);
	
	return status;
}


/*===========================================================================
FUNCTION:  ustc_sdc_init

DESCRIPTION: 
 	initialize SD controler, and identify card info
INPUT PARAMETER:

OUTPUT PARAMETER:  

RETURN VALUE:
===========================================================================*/
STATUS_T ustc_sdc_init(SD_PARA_T * para_sd)
{
	STATUS_T status = RSP_SUCCESS;
	USTC_U32	count;
	CSD_T	csd;
	USTC_U32	r1,r2,r3,r4;
	USTC_U16	card_type =0;


	//store parameters
	gp_para_sd = para_sd;
	
	gp_para_sd->sd_block_number = 0;
	/*rst sd controller */
//	ustc_io_reset_module(MODULE_SD);

//	gp_para_sd->sd_clk_div=USTC_IO_INW(HW_SD_CLK_CON);
	//configure SD clock
	USTC_IO_OUTW(HW_SD_CLK_DFG, gp_para_sd->sd_clk_phase_cfg);		// disable block_write_en

	/* mask "cmd sent", "card exit", "card removed" */
	USTC_IO_OUTW(HW_SD_MASK, SD_MASK_10_11_12);
	
	/* disable card detect */
	USTC_IO_OUTW(HW_SD_SRAM_RDCLK_CON, SD_CD_INVALID);

	/* Set time out */
	USTC_IO_OUTW(HW_SD_TIMEOUT, SD_TIMEOUT_10ms);

	do
	{
		/* rst sd card   card -> idle*/
		USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD0);	
		status = sd_wait_cmd_done(1);
		if (status)
			break;
		if (gp_para_sd->ustc_sdc_init_delay1)
			ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card

		/*check card type and trans state idle->ready*/
		status = 0;
		USTC_IO_OUTW(HW_SD_CMD_ARG, 0);   
		USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD55);	
		status = sd_wait_cmd_done(1);

		if (RSP_SUCCESS == status)
			card_type =SD_TYPE_SD;			//SD card
		else if (status & RSP_SD_CMD_TIMEOUT)
			card_type =SD_TYPE_MMC;//MMC card or no card
		else
			break;

		if (gp_para_sd->ustc_sdc_init_delay1)
			ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card

		/******************************
		send cmd 55,
		send acmd 41
		idle -> ready (when card not busy)
		or
		idle -> idle (card still busy)
		or
		idle -> inactive (voltage not compitable or acmd 41 ask card to)
		*******************************/
		if (SD_TYPE_SD==card_type)
		{
			/* send ACMD41 command, SD card state changed from "idle state" to "Ready State" */
			USTC_IO_OUTW(HW_SD_CMD_ARG, SD_CMDARG_ACMD41);   
			USTC_IO_OUTW(HW_SD_CMD_CON, SD_ACMD41);	
			status = sd_wait_cmd_done(0);
			if (status)
				break;
			if (gp_para_sd->ustc_sdc_init_delay1)
				ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card
			
			count=0;
#if (0)
			do
			{
				count++;
				if (count >=100)
				{
					status = RSP_SD_CMD_RSP_ERR;
					break;
				}
				/* send cmd55 command ,SD card will send ACMD command */
				USTC_IO_OUTW(HW_SD_CMD_ARG, 0);   
				USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD55);	
				status = sd_wait_cmd_done(1);

				if (gp_para_sd->ustc_sdc_init_delay1)
					ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card
				if (status)
					continue;
				
				/* send ACMD41 command, SD card state changed from "idle state" to "Ready State" */
				USTC_IO_OUTW(HW_SD_CMD_ARG, SD_CMDARG_ACMD41);   
				USTC_IO_OUTW(HW_SD_CMD_CON, SD_ACMD41);	
				status = sd_wait_cmd_done(0);
				
				if (gp_para_sd->ustc_sdc_init_delay1)
					ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card
				if (status)
					continue;
			}while (!USTC_IO_INWM(HW_SD_RSP_ARG1, SD_CARD_READY));
			#else
			while (!USTC_IO_INWM(HW_SD_RSP_ARG1, SD_CARD_READY))
			{
				count++;
				if (count >=100)
				{
					status = RSP_SD_CMD_RSP_ERR;
					break;
				}
				/* send cmd55 command ,SD card will send ACMD command */
				USTC_IO_OUTW(HW_SD_CMD_ARG, 0);   
				USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD55);	
				status = sd_wait_cmd_done(1);

				if (gp_para_sd->ustc_sdc_init_delay1)
					ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card

				if (status)
					continue;
				
				/* send ACMD41 command, SD card state changed from "idle state" to "Ready State" */
				USTC_IO_OUTW(HW_SD_CMD_ARG, SD_CMDARG_ACMD41);   
				USTC_IO_OUTW(HW_SD_CMD_CON, SD_ACMD41);	
				status = sd_wait_cmd_done(0);

				if (gp_para_sd->ustc_sdc_init_delay1)
					ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card
					
				if (status)
					continue;
			}
			#endif
			if (status)
				break;
		}
		else
		{
			/* rst sd card   card -> idle*/
			USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD0);
			if (gp_para_sd->ustc_sdc_init_delay2)
				ustc_delay(gp_para_sd->ustc_sdc_init_delay2);//needed by some SD Card
			status = sd_wait_cmd_done(1);
			if (status)
				break;
			if (gp_para_sd->ustc_sdc_init_delay1)
				ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card

			count = 0;
			do
			{
				count++;
				if (count >=100)
				{
					status = RSP_SD_CMD_RSP_ERR;
					break;
				}
				USTC_IO_OUTW(HW_SD_CMD_ARG, SD_CMDARG_ACMD41);   /* OCR*/
				USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD1);	
				if (gp_para_sd->ustc_sdc_init_delay2)
					ustc_delay(gp_para_sd->ustc_sdc_init_delay2);//needed by some SD Card
				status = sd_wait_cmd_done(0);
				if (gp_para_sd->ustc_sdc_init_delay1)
					ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card	
				if (status)
					continue;
			} while(USTC_IO_INWM(HW_SD_RSP_ARG1, SD_CARD_READY));
		}
	
		
		if (gp_para_sd->ustc_sdc_init_delay2)
			ustc_delay(gp_para_sd->ustc_sdc_init_delay2);//needed by some SD Card
		
	
		/* send CMD2 command SD card state changed from "Ready State" to "identification State" */
		USTC_IO_OUTW(HW_SD_CMD_ARG, 0);   
		USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD2);	
		status = sd_wait_cmd_done(1);
		if (status)
			break;
		if (gp_para_sd->ustc_sdc_init_delay1)
			ustc_delay(gp_para_sd->ustc_sdc_init_delay1);

		if (gp_para_sd->ustc_sdc_init_delay2)
			ustc_delay(gp_para_sd->ustc_sdc_init_delay2);//needed by some SD Card
			
		/* send cmd 3 identify -> standby */
		if (card_type ==SD_TYPE_SD)
		{
			USTC_IO_OUTW(HW_SD_CMD_ARG, 0);   
			USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD3);	
			status = sd_wait_cmd_done(1);
			if (status)
				break;
			if (gp_para_sd->ustc_sdc_init_delay1)
				ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card
			
			/* get in rca, and format is 0x????0000 */
			gp_para_sd->sd_rca = USTC_IO_INWM(HW_SD_RSP_ARG1, SD_CARD_RCA);
		}
		else
		{
			USTC_IO_OUTW(HW_SD_CMD_ARG, SD_RCA_FOR_MMC);   
			USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD3);	
			status = sd_wait_cmd_done(1);
			if (status)
				break;
			if (gp_para_sd->ustc_sdc_init_delay1)
				ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card
		
			/* get in rca, and format is 0x????0000 */
			gp_para_sd->sd_rca=SD_RCA_FOR_MMC;
		}

		/* read CSD parameter */
		USTC_IO_OUTW(HW_SD_CMD_ARG, gp_para_sd->sd_rca);
		USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD9);	
		status = sd_wait_cmd_done(1);
		if (status)
			break;
		if (gp_para_sd->ustc_sdc_init_delay1)
			ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card

		/* 16M sd card data  */
		/* r4 is high bit */	
		r4=USTC_IO_INW(HW_SD_RSP_ARG4);  //0x20002d00
		r3=USTC_IO_INW(HW_SD_RSP_ARG3);	//0x32135980
		r2=USTC_IO_INW(HW_SD_RSP_ARG2);	//0xe376d9cf
		r1=USTC_IO_INW(HW_SD_RSP_ARG1);	//0x80164000
	
		csd.read_block_len =(r3&0x00000f00)>>8;
		csd.c_size =((r2&0xffc00000)>>22)|((r3&0x03)<<10);
		csd.c_size_mult =(r2&0x380)>>7;
		gp_para_sd->sd_block_len= 1 << csd.read_block_len ;						//0x200
		gp_para_sd->sd_block_number =((USTC_U32)1<<(csd.c_size_mult+2))*((USTC_U32)csd.c_size+1);    //0x000071c0

		gp_para_sd->sd_block_number <<= (csd.read_block_len-9);
		gp_para_sd->sd_block_len = 512;
	
		if (gp_para_sd->ustc_sdc_init_delay2)
			ustc_delay(gp_para_sd->ustc_sdc_init_delay2);//needed by some SD Card
	
	
		/* send cmd 7 standby -> tranfer */
		USTC_IO_OUTW(HW_SD_CMD_ARG, gp_para_sd->sd_rca);
		USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD7);	
		status = sd_wait_cmd_done(1);
		if (status)
			break;
		if (gp_para_sd->ustc_sdc_init_delay1)
			ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card

		if (card_type==SD_TYPE_SD)
		{
			/*	send acmd 42 clear card detect */	
			/* send cmd 55  */
			USTC_IO_OUTW(HW_SD_CMD_ARG, gp_para_sd->sd_rca);
			USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD55);	
			status = sd_wait_cmd_done(1);
			if (status)
				break;
			if (gp_para_sd->ustc_sdc_init_delay1)
				ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card
			
			//==== send acmd 42 ====//
			USTC_IO_OUTW(HW_SD_CMD_ARG, SD_CMDARG_CLRCD);
			USTC_IO_OUTW(HW_SD_CMD_CON, SD_ACMD42);	
			status = sd_wait_cmd_done(1);
			if (status)
				break;
			if (gp_para_sd->ustc_sdc_init_delay1)
				ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card

			/* set card size */
			USTC_IO_OUTW(HW_SD_CMD_ARG, gp_para_sd->sd_rca);
			USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD55);	
			status = sd_wait_cmd_done(1);
			if (status)
				break;
			if (gp_para_sd->ustc_sdc_init_delay1)
				ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card

			//----send acmd6
			USTC_IO_OUTW(HW_SD_CMD_ARG, SD_CMDARG_1W);
			USTC_IO_OUTW(HW_SD_CMD_CON,SD_ACMD6);	
			status = sd_wait_cmd_done(1);
			if (status)
				break;
			if (gp_para_sd->ustc_sdc_init_delay1)
				ustc_delay(gp_para_sd->ustc_sdc_init_delay1);//needed by some SD Card
		}

		/* change clock divisor */
		USTC_IO_OUTW(HW_SD_CLK_CON, gp_para_sd->sd_clk_div);
	}while (0);

	//can't identify SD card
	if (gp_para_sd->sd_block_number==0)
		status = RSP_SD_CMD_RSP_ERR;
	if (status)
		gp_para_sd->sd_block_number = 0;

	return status;
}

static unsigned long ustc_sdc_read_block(unsigned long *p_buffer, unsigned long block_index)
{
	unsigned long i;
	STATUS_T ret_val=RSP_SUCCESS;
	
	/* change clock to 1/2 divide */
	USTC_IO_OUTW(HW_SD_CLK_CON, gp_para_sd->sd_clk_div);

	/* Set time out */
	USTC_IO_OUTW(HW_SD_TIMEOUT, SD_TIMEOUT_100ms);

	//==============read card==============
	/*---- set data length is 512 */
	USTC_IO_OUTW(HW_SD_DATA_LEN, (SD_BLOCK_SIZE-1));
	/*----set data control register */
	USTC_IO_OUTW(HW_SD_DATA_CON, ((USTC_U32)(SD_BLOCK_SIZE-1)<<16)|SD_RD_1W );   //SD_RD_B512_4W
//	USTC_IO_OUTW(HW_SD_DATA_CON, ((USTC_U32)(SD_BLOCK_SIZE-1)<<16)|SD_RD_4W );   // 4 wire mode

	//----send cmd 17 to card
	// write address into cmd argument
	USTC_IO_OUTW(HW_SD_CMD_ARG, block_index * SD_BLOCK_SIZE);
	USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD17);

	sd_wait_data_done();

	//==============read fifo==============
	for(i = 0; i < SD_BLOCK_SIZE/4; i+=8)
	{
		//fifo_full = USTC_IO_INW(HW_SD_FIFO_COUNTER);
		//while(fifo_full & 0x8000);
		ustc_io_burst_inw(SD_FIFO_ADDR, p_buffer);
		p_buffer+=8;
	}

	ustc_sw_reset(HIF_RST_SD, 1);
	
	/* change clock to 1/2 divide */
	USTC_IO_OUTW(HW_SD_CLK_CON, gp_para_sd->sd_clk_div);

	/* Set time out */
	USTC_IO_OUTW(HW_SD_TIMEOUT, SD_TIMEOUT_100ms);
		
	return ret_val;
}

static unsigned long ustc_sdc_write_block(unsigned long *p_buffer, unsigned long block_index)
{
	unsigned long i;
	USTC_U32		status=0,count;
	STATUS_T	ret_val=RSP_SUCCESS;


	/* change clock to 1/2 divide */
	USTC_IO_OUTW(HW_SD_CLK_CON, gp_para_sd->sd_clk_div);

	/* Set time out */
	USTC_IO_OUTW(HW_SD_TIMEOUT, SD_TIMEOUT_100ms);

	//==============enable data==============
	USTC_IO_OUTW(HW_SD_CLK_DFG, 0x10|gp_para_sd->sd_clk_phase_cfg);		// enable block_write_en
	USTC_IO_OUTW(HW_SD_DATA_CON, 0x100);		//enable REG_SD_TRAN_DATA_EN
	
	//==============write fifo==============
	for(i = 0; i < SD_BLOCK_SIZE/4; i+=8)
	{
		ustc_io_burst_outw(SD_FIFO_ADDR, p_buffer);
		p_buffer+=8;
	}

	//==============write card==============
	USTC_IO_OUTW(HW_SD_CMD_ARG, block_index * SD_BLOCK_SIZE);
	USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD24);	
	sd_wait_cmd_done(1);

	/* this command is used by debug */
	USTC_IO_OUTW(HW_SD_CMD_ARG, gp_para_sd->sd_rca);
	USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD13);	
	sd_wait_cmd_done(1);
	
	//----clear status register
	USTC_IO_OUTW(HW_SD_STATUS, SD_CLR_STATUS);  
	//----set data length
	USTC_IO_OUTW(HW_SD_DATA_LEN, (SD_BLOCK_SIZE-1));
	//----set data control register
	USTC_IO_OUTW(HW_SD_DATA_CON, ((USTC_U32)(SD_BLOCK_SIZE-1)<<16)|SD_WR_1W);
//	USTC_IO_OUTW(HW_SD_DATA_CON, ((USTC_U32)(SD_BLOCK_SIZE-1)<<16)|SD_WR_4W);  // 4 wire mode

	sd_wait_data_done();

	//----send cmd 13 to check card status
	count=0;
	if (RSP_SUCCESS==ret_val) do
	{
		USTC_IO_OUTW(HW_SD_CMD_ARG, gp_para_sd->sd_rca);
		USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD13);	
		sd_wait_cmd_done(1);
		
		if(++count == SD_CMD_TIME_OUT) {
			ret_val = FS_CMD_TIME_OUT;
			break;
		}
	} while (!USTC_IO_INWM(HW_SD_RSP_ARG1, SD_RDY4DATA));

	//----check whether rcv error
	if(USTC_IO_INWM(HW_SD_RSP_ARG1, SD_RCV_ERROR))
		ret_val=FS_WRITE_BLOCK_FAIL;

	ustc_sw_reset(HIF_RST_SD, 1);

	USTC_IO_OUTW(HW_SD_CLK_DFG, 0x0|gp_para_sd->sd_clk_phase_cfg);		// disable block_write_en

	
	/* change clock to 1/2 divide */
	USTC_IO_OUTW(HW_SD_CLK_CON, gp_para_sd->sd_clk_div);

	/* Set time out */
	USTC_IO_OUTW(HW_SD_TIMEOUT, SD_TIMEOUT_100ms);

	if (status
		&(SD_CMD_DONE_CRC_ERR
		| SD_CMD_DONE_TIMER_ERR
		| SD_DATA_DONE_CRC_ERR
		| SD_DATA_DONE_TIMEOUT
		| SD_DATA_DONE_FIFO_OVER_ERR
		| SD_DATA_DONE_FIFO_UNDER_ERR))
		ret_val=1;
	
	return ret_val;
}

STATUS_T ustc_sdc_read(unsigned long *p_buffer, unsigned long block_index, unsigned long num)
{
	STATUS_T ret;

	while (num--)
	{
		ret=ustc_sdc_read_block(p_buffer, block_index);
		p_buffer+=128;
		block_index++;
	}

	return ret;
}

STATUS_T ustc_sdc_write(unsigned long *p_buffer, unsigned long block_index, unsigned long num)
{
	STATUS_T ret;

	while (num--)
	{
		ret=ustc_sdc_write_block(p_buffer, block_index);
		p_buffer+=128;
		block_index++;
	}

	return ret;
}

void ustc_sdc_read_start(unsigned long blk)
{
	USTC_IO_OUTW(HW_SD_TIMEOUT, SD_TIMEOUT_100ms);
	//==============read card==============
	/*---- set data length is 512 */
	USTC_IO_OUTW(HW_SD_DATA_LEN, (SD_BLOCK_SIZE-1));
	/*----set data control register */
	USTC_IO_OUTW(HW_SD_DATA_CON, ((USTC_U32)(SD_BLOCK_SIZE-1)<<16)|SD_RD_1W );   //SD_RD_B512_4W

	//----send cmd 17 to card
	// write address into cmd argument
	USTC_IO_OUTW(HW_SD_CMD_ARG, blk * SD_BLOCK_SIZE);
	USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD17);
}

void ustc_sdc_write_start(unsigned long blk)
{
	USTC_IO_OUTW(HW_SD_TIMEOUT, SD_TIMEOUT_100ms);

	//==============enable data==============
	USTC_IO_OUTW(HW_SD_CLK_DFG, 0x10|gp_para_sd->sd_clk_phase_cfg);		// enable block_write_en
	USTC_IO_OUTW(HW_SD_DATA_CON, 0x100);		//enable REG_SD_TRAN_DATA_EN
	
	//==============write card==============
	USTC_IO_OUTW(HW_SD_CMD_ARG, blk * SD_BLOCK_SIZE);
	USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD24);	
	sd_wait_cmd_done(1);

	/* this command is used by debug */
	USTC_IO_OUTW(HW_SD_CMD_ARG, gp_para_sd->sd_rca);
	USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD13);	
	sd_wait_cmd_done(1);
	
	//----clear status register
	USTC_IO_OUTW(HW_SD_STATUS, SD_CLR_STATUS);  
	//----set data length
	USTC_IO_OUTW(HW_SD_DATA_LEN, (SD_BLOCK_SIZE-1));
	//----set data control register
	USTC_IO_OUTW(HW_SD_DATA_CON, ((USTC_U32)(SD_BLOCK_SIZE-1)<<16)|SD_WR_1W);
}

void ustc_sdc_read_fifo(unsigned long *buf)
{
	int i;
	
	for(i = 0; i < SD_BLOCK_SIZE/4; i+=8)
	{
		ustc_io_burst_inw(SD_FIFO_ADDR, buf);
		buf+=8;
	}
}

void ustc_sdc_write_fifo(unsigned long *buf)
{
	int i;
	for(i = 0; i < SD_BLOCK_SIZE/4; i+=8)
	{
		ustc_io_burst_outw(SD_FIFO_ADDR, buf);
		buf+=8;
	}

}

STATUS_T ustc_sdc_card_state()
{
	USTC_IO_OUTW(HW_SD_CMD_ARG, gp_para_sd->sd_rca);
	USTC_IO_OUTW(HW_SD_CMD_CON, SD_CMD13);	
	sd_wait_cmd_done(1);
		
	return USTC_IO_INW(HW_SD_RSP_ARG1);
}

void ustc_sdc_set_clk(USTC_U16 clk_div)
{
	USTC_IO_OUTW(HW_SD_CLK_CON, clk_div);
}
